#include "Shader.h"

Shader::Shader(const GLchar * vertexPath, const GLchar * fragPath)
{

	std::string vertexCode;
	std::string fragmentCode;
	std::ifstream vShaderFile;
	std::ifstream fShaderFile;

	//ensure ifstream can throw exception
	vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
	fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);

	try
	{
		vShaderFile.open(vertexPath);
		fShaderFile.open(fragPath);
		std::stringstream vShaderStrem, fShaderStream;
		//read file buffer contents into stream
		vShaderStrem << vShaderFile.rdbuf();
		fShaderStream << fShaderFile.rdbuf();
		vShaderFile.close();
		fShaderFile.close();

		//convert stream into string
		vertexCode = vShaderStrem.str();
		fragmentCode = fShaderStream.str();

	}
	catch (const std::ifstream::failure e)
	{
		std::cout << " error shader file not success read " << std::endl;
	}

	const char* vShaderCode = vertexCode.c_str();
	const char* fShaderCode = fragmentCode.c_str();
	//2.compile shader
	unsigned int vertex, fragment;
	vertex = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertex, 1, &vShaderCode, NULL);
	glCompileShader(vertex);

	fragment = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragment, 1, &fShaderCode, NULL);
	glCompileShader(fragment);

	//shder program
	programe = glCreateProgram();
	glAttachShader(programe, vertex);
	glAttachShader(programe, fragment);
	glLinkProgram(programe);


	glDeleteShader(vertex);
	glDeleteShader(fragment);
}

void Shader::use()
{
	glUseProgram(programe);
}

void Shader::setBool(const std::string & name, bool value) const
{
	glUniform1i(glGetUniformLocation(programe, name.c_str()), (int )value);
}

void Shader::setInt(const std::string & name, int value) const
{
	glUniform1i(glGetUniformLocation(programe, name.c_str()), value);
}

void Shader::setFloat(const std::string & name, float value) const
{
	glUniform1f(glGetUniformLocation(programe, name.c_str()), value);
}

void Shader::setMat4(const std::string & name, glm::mat4 value) const
{
	glUniformMatrix4fv(glGetUniformLocation(programe, name.c_str()), 1, GL_FALSE, glm::value_ptr(value));
}

void Shader::setVec3(const std::string & name, glm::vec3 value) const
{
	glUniform3f(glGetUniformLocation(programe, name.c_str()), value.x, value.y, value.z);
}

void Shader::CHECKCompileError(unsigned int shader, std::string type)
{
	int success;
	char infoLog[1024];
	if (type != "PROGRAME") {
		glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
		if (!success) {
			glGetShaderInfoLog(shader, 1024, NULL, infoLog);
			std::cout << "Shader compiler error: " << infoLog << std::endl;
		}
		else
		{
			glGetProgramiv(shader, GL_LINK_STATUS, &success);
			if (!success) {
				glGetProgramInfoLog(shader, 1024, NULL, infoLog);
				std::cout << "programe link failed! ==> " << infoLog << std::endl;
			}
		}
	}

}
